package cn.datax.service.data.market.utils;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description RAS加密工具类
 * @Author songwp
 * @Date 2022/8/8 20:34
 * @Version 1.0.0
 **/
public class RSAUtil {
    protected static Logger log = LoggerFactory.getLogger(RSAUtil.class);

    private static final String KEY_ALGORITHM = "RSA";
    //密钥长度
            private static final int KEY_SIZE = 4096;

    //最大加密长度
            private static final int MAX_ENCRYPT_BLOCK = KEY_SIZE / 8 -11;
    //最大解密长度
            private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / 8;

    private static String getRsaKey() {
        return "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";
    }

    private static byte[] decryptBASE64(String src) {
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            return decoder.decodeBuffer(src);
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 生成公私钥
     *
     * @param keySize 密钥长度
     */
    public static Map<String, String> genKeyPair(int keySize) {
        Map<String, String> keyMap = new HashMap<>();
        try {
            //创建密钥对生成器
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(keySize);
            //生成密钥对
            KeyPair keyPair = kpg.generateKeyPair();
            //公钥
            PublicKey publicKey = keyPair.getPublic();
            //私钥
            PrivateKey privateKey = keyPair.getPrivate();
            keyMap.put("publicKey", Base64.encodeBase64String(publicKey.getEncoded()));
            keyMap.put("privateKey", Base64.encodeBase64String(privateKey.getEncoded()));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            log.error("生成公私钥信息失败："+e.getMessage());
        }
        return keyMap;
    }


    /**
     * 该base64方法会自动换行
     * @param src
     * @return
     */
    private static String encryptBASE64(byte[] src) {
        BASE64Encoder encoder = new BASE64Encoder();

        return encoder.encode(src);
    }
    /**
     * 公钥分段加密
     * @param data 源数据
     * @param publicKey 公钥(BASE64编码)
     * @param length 段长
     * @return
     * @throws Exception
     */
    private static byte[] encryptByPublicKey(byte[] data, String publicKey,int length) {
        ByteArrayOutputStream out = null;
        byte[] encryptData = null;
        try {
            byte[] keyBytes = decryptBASE64(publicKey);
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Key publicK = keyFactory.generatePublic(x509KeySpec);
            // 对数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicK);
            int inputLen = data.length;
            out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > length) {
                    cache = cipher.doFinal(data, offSet, length);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * length;
            }
            encryptData = out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("公钥分段加密失败："+e.getMessage());
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return encryptData;
    }

/** *//**
     * <P>
     * 私钥解密
     * </p>
     *
     * @param data 已加密数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    private static byte[] decryptByPrivateKey(byte[] data, String privateKey,int length){
        ByteArrayOutputStream out = null;
        byte[] decryptedData = null;
        try {
            byte[] keyBytes =  decryptBASE64(privateKey);
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateK);
            int inputLen = data.length;
            out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > length) {
                    cache = cipher.doFinal(data, offSet, length);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * length;
            }
            decryptedData = out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("私钥解密失败："+e.getMessage());
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return decryptedData;
    }

    /**
     * 加密
     * @param data
     * @param publicKey
     * @return
     */
    public static String encryptByPublicKey(String data, String publicKey) {
        //log.info("公钥分段加密内容："+new String(encryptByPublicKey(data.getBytes(), publicKey, MAX_ENCRYPT_BLOCK)).replaceAll("[+]", "@"));
        return encryptBASE64(encryptByPublicKey(data.getBytes(), publicKey, MAX_ENCRYPT_BLOCK)).replaceAll("[+]", "@");
    }

    /**
     * 解密
     * @param data
     * @return
     */
    public static String decryptByPrivateKey(String data) {
        //log.info("私钥解密内容："+new String(decryptByPrivateKey(decryptBASE64(data.replaceAll("@", "+")), getRsaKey(), MAX_DECRYPT_BLOCK)));
        return new String(decryptByPrivateKey(decryptBASE64(data.replaceAll("@", "+")), getRsaKey(), MAX_DECRYPT_BLOCK));
    }
//    public static void main(String[] args) {
//        Map<String, String> keyMap = genKeyPair(KEY_SIZE); System.out.println("公钥======"+keyMap.get("publicKey"));
//        System.out.println("私钥======"+keyMap.get("privateKey"));
//        String encryptString = encryptByPublicKey("{\\\"allBillList\\\":[{\\\"id\\\":\\\"264786\\\",\\\"billNo\\\":\\\"WB2021051700064\\\",\\\"billTypeId\\\":13,\\\"billTypeName\\\":\\\"定损维修\\\",\\\"vehicleNo\\\":\\\"京Q683976\\\",\\\"vehicleId\\\":\\\"532928\\\",\\\"vehicleOwner\\\":\\\"北京测试公司\\\",\\\"vehicleModelName\\\":\\\"宝马\\\",\\\"orderCar\\\":0,\\\"orderCarName\\\":\\\"短租\\\",\\\"cityId\\\":null,\\\"cityName\\\":\\\"北京\\\",\\\"deptId\\\":null,\\\"deptName\\\":\\\"北京测试\\\",\\\"nowCityId\\\":null,\\\"nowCityName\\\":null,\\\"nowDeptId\\\":null,\\\"nowDeptName\\\":null,\\\"belongCityId\\\":null,\\\"belongCityName\\\":\\\"北京\\\",\\\"belongDeptId\\\":null,\\\"belongDeptName\\\":\\\"知春路店\\\",\\\"costBelongAreaName\\\":\\\"知春路大片区\\\",\\\"costBelongCityName\\\":\\\"北京\\\",\\\"costBelongDeptName\\\":\\\"知春路店\\\",\\\"createTime\\\":\\\"2021-05-17 10:11\\\",\\\"modifyTime\\\":null,\\\"billStatusId\\\":109,\\\"billStatusName\\\":\\\"方案已通过\\\",\\\"createEmpName\\\":\\\"JD\\\",\\\"createEmpDeptName\\\":\\\"北京测试\\\",\\\"pickupType\\\":2,\\\"pickupTypeName\\\":\\\"上门\\\",\\\"isDelete\\\":0,\\\"isDeleteeName\\\":\\\"否\\\",\\\"garageId\\\":null}],\\\"totalCount\\\":1}\";\n","MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnvGvwKuIfZdWilPI+nT/Pas1N6b3Jns7D9oK698h1j8yzmpD9KnM5hHCgl4toEVg4R4KEsJTTmUe9HU1dBTQby9TnBH5w5UeQgg/Mx5sJ3w5DyAPu2njOhU/5aoSInowpa5JLoba0YIzQWn++a/jhJs50T+Wt+xy3WEbF3QYN/Y7m0ZN1C70KXlX2xOLI8BL80BMqLF3Q1dIkvxLmxalJZiEnvkALWly8pERrvvz1YX6rKWOo1wtS5AJW1xrctnOf4saQi9/Jv0PRnkuFRo9BB1RZA/vV5kPt++szrCi7qDRCokAoQfn8enB1UJNED/tFWwqxpzZ+ic+C+FfLrxZ7nXocWMQWSojrIhY7+2TYT3fwO4ZvJoKlg71R6H+gSr2p0qBye+ELIeEr83UWMhvKrcAP0FpJcWpWpJaMKGo5yjUe4u7FBKF5j+O0GJCTfkxA8aw+KTZ/PnyoEI65PGD7i4XQWrvTPkyMcfMy9/dXd8efqzh5kg3kAauHvTBLcSpjRqCFT3pz6bK0azegrGPlIEPa3W5UzZ0MkhtM+6nbrOKgzuj27glwHRBNbhs8bllzVGU4+Zxv98lUp8VvPsVMweOHB4Zz/g+dLamHcMA0xLPPHZJRwvBbsm6rWd96Wcm0Y3ZyyIGMsj0AWPBjMvbHcBCJDFTxIMZ9GOAIMuU+lcCAwEAAQ==");
//       System.out.println("密文======"+encryptString); String decryptString = decryptByPrivateKey(encryptString);
//        System.out.println("明文======"+decryptString);
//    }
}
